package com.caoustc.okhttplib.okhttp.platform

import java.io.IOException
import java.io.UnsupportedEncodingException
import java.security.GeneralSecurityException
import java.security.MessageDigest
import java.util.*
import kotlin.experimental.and

/**
 * Created by cz on 2018/3/12.
 */
object SignUtils {
    fun sign(paramValues: Map<String, String?>, sign: String?, sign_method: String): String {
        return sign(paramValues, null, sign, sign_method)
    }

    fun sign(
        paramValues: Map<String, String?>,
        ignoreParamNames: List<String?>?,
        secret: String?,
        sign_method: String
    ): String {
        var sign_method = sign_method
        return try {
            val sb = StringBuilder()
            val paramNames: MutableList<String> = ArrayList<String>(paramValues.size)
            paramNames.addAll(paramValues.keys)
            if (ignoreParamNames != null && ignoreParamNames.size > 0) {
                for (ignoreParamName in ignoreParamNames) {
                    paramNames.remove(ignoreParamName)
                }
            }
            Collections.sort(paramNames.toList())
            sb.append(secret)
            for (paramName in paramNames) {
                var value = paramValues[paramName as String?]
                value = if (notBlank(value)) value else ""
                sb.append(paramName).append(value)
            }
            sb.append(secret)
            var digests: ByteArray? = null
            sign_method = sign_method.toLowerCase()
            digests = if (PlatformConstants.sign_method_MD5 == sign_method) {
                getMD5Digest(sb.toString())
            } else {
                getSHA1Digest(sb.toString())
            }
            byte2hex(digests)
        } catch (e: IOException) {
            throw RuntimeException("apigetway sign error:" + e.message)
        }
    }

    fun utf8Encoding(value: String, sourceCharsetName: String?): String {
        return try {
            String(value.toByteArray(charset(sourceCharsetName!!)), charset("UTF-8"))
        } catch (e: UnsupportedEncodingException) {
            throw IllegalArgumentException(e)
        }
    }

    @Throws(IOException::class)
    private fun getSHA1Digest(data: String): ByteArray? {
        var bytes: ByteArray? = null
        bytes = try {
            val md = MessageDigest.getInstance("SHA-1")
            md.digest(data.toByteArray(charset("UTF-8")))
        } catch (gse: GeneralSecurityException) {
            throw IOException(gse)
        }
        return bytes
    }

    @Throws(IOException::class)
    private fun getMD5Digest(data: String): ByteArray? {
        var bytes: ByteArray? = null
        bytes = try {
            val md = MessageDigest.getInstance("MD5")
            md.digest(data.toByteArray(charset("UTF-8")))
        } catch (gse: GeneralSecurityException) {
            throw IOException(gse)
        }
        return bytes
    }

    private fun byte2hex(bytes: ByteArray?): String {
        val sign = StringBuilder()
        for (i in bytes!!.indices) {
            val hex = Integer.toHexString(0xFF and bytes[i].toInt())
            if (hex.length == 1) {
                sign.append("0")
            }
            sign.append(hex.toUpperCase())
        }
        return sign.toString()
    }

    val uUID: String
        get() {
            val uuid = UUID.randomUUID()
            return uuid.toString().toUpperCase()
        }

    fun sign(sign_method: String?, parmsvalue: String): String {
        var sign_method = sign_method
        return try {
            var digests: ByteArray? = null
            sign_method = sign_method!!.toLowerCase()
            digests = if (PlatformConstants.sign_method_MD5 == sign_method) {
                getMD5Digest(parmsvalue)
            } else {
                getSHA1Digest(parmsvalue)
            }
            byte2hex(digests)
        } catch (e: IOException) {
            throw RuntimeException("apigetway sign error:" + e.message)
        }
    }

    private fun isBlank(str: String?): Boolean {
        if (str == null) {
            return true
        }
        val len = str.length
        if (len == 0) {
            return true
        }
        for (i in 0 until len) {
            when (str[i]) {
                '\t', '\n', '\r', ' ' -> {
                }
                else -> return false
            }
        }
        return true
    }

    private fun notBlank(str: String?): Boolean {
        return !isBlank(str)
    }
}